package com.letoken.platform.repo.awss3.service;


import com.alibaba.fastjson2.JSON;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.letoken.platform.pub.configuration.AwsS3Configuration;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import software.amazon.awssdk.auth.credentials.ProfileCredentialsProvider;
import software.amazon.awssdk.profiles.ProfileFileSupplier;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.rekognition.RekognitionClient;
import software.amazon.awssdk.services.rekognition.model.*;
import software.amazon.awssdk.services.sqs.SqsClient;
import software.amazon.awssdk.services.sqs.model.DeleteMessageRequest;
import software.amazon.awssdk.services.sqs.model.Message;
import software.amazon.awssdk.services.sqs.model.ReceiveMessageRequest;
import software.amazon.awssdk.utils.SystemSetting;
import software.amazon.awssdk.utils.UserHomeDirectoryUtils;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.nio.file.Paths;
import java.util.*;

@Service
@Slf4j
public class AWSRekognitionService {

    private static RekognitionClient rekClient;
    private static SqsClient sqs;
    private static NotificationChannel channel;

    private static final String queueUrl = "https://sqs.ap-southeast-1.amazonaws.com/144993035849/VideoContentDetectionQueue";

    private static final ReceiveMessageRequest messageRequest = ReceiveMessageRequest.builder()
            .queueUrl(queueUrl)
            .build();

    @Resource
    private AwsS3Configuration awsS3Configuration;

    @PostConstruct
    private void rekognitionInit() {

        ProfileCredentialsProvider profileCredentialsProvider = ProfileCredentialsProvider
                .builder()
                .profileFile(ProfileFileSupplier.defaultSupplier())
                .build();

        rekClient = RekognitionClient.builder()
                .region(Region.AP_SOUTHEAST_1)
                .credentialsProvider(profileCredentialsProvider)
                .build();

        sqs = SqsClient.builder()
                .region(Region.AP_SOUTHEAST_1)
                .credentialsProvider(profileCredentialsProvider)
                .build();

        channel = NotificationChannel.builder()
                .snsTopicArn("arn:aws:sns:ap-southeast-1:144993035849:AmazonRekognitionVideoContentDetection")
                .roleArn("arn:aws:iam::144993035849:role/vediosns")
                .build();
    }


    public String videoModerationDetection(String videoPath) {
        log.info("start videoModerationDetection video path:{}", videoPath);
        S3Object s3Obj = S3Object.builder()
                .bucket(awsS3Configuration.getBucketName())
                .name(videoPath)
                .build();
        Video vidOb = Video.builder()
                .s3Object(s3Obj)
                .build();
        StartContentModerationRequest labelDetectionRequest = StartContentModerationRequest.builder()
                .jobTag("DetectModerationLabels")
                .notificationChannel(channel)
                .video(vidOb)
                .minConfidence(50F)
                .build();
        return rekClient.startContentModeration(labelDetectionRequest).jobId();
    }

    public List<AwsApiResult> receiveMessages() {


        try {
            List<Message> messages = sqs.receiveMessage(messageRequest).messages();
            if (!messages.isEmpty()) {
                List<AwsApiResult> results = new ArrayList<>(messages.size());
                for (Message message : messages) {
                    ObjectMapper mapper = new ObjectMapper();
                    JsonNode jsonMessageTree = mapper.readTree(message.body());
                    JsonNode messageBodyText = jsonMessageTree.get("Message");
                    ObjectMapper operationResultMapper = new ObjectMapper();
                    JsonNode jsonResultTree = operationResultMapper.readTree(messageBodyText.textValue());
                    JsonNode operationJobId = jsonResultTree.get("JobId");
                    JsonNode operationStatus = jsonResultTree.get("Status");

                    JsonNode statusMessage = jsonResultTree.get("Message");
                    results.add(new AwsApiResult(operationStatus.textValue(), operationJobId.textValue(), message.receiptHandle(), null == statusMessage ? null : statusMessage.textValue()));
                }
                return results;
            }
        } catch (RekognitionException | JsonProcessingException e) {
            log.error("error to receive messages;", e);
        }
        return null;
    }

    public List<Map<String, String>> videoModerationDetectionResult(String jobId) {
        try {
            GetContentModerationRequest contentModerationRequest = GetContentModerationRequest.builder()
                    .jobId(jobId)
                    .maxResults(100)
                    .build();

            GetContentModerationResponse contentModerationResponse = rekClient.getContentModeration(contentModerationRequest);
            if (null != contentModerationResponse && contentModerationResponse.jobStatus().name().equals("SUCCEEDED")) {
                if (!CollectionUtils.isEmpty(contentModerationResponse.moderationLabels())) {
                    List<Map<String, String>> labels = new ArrayList<>(contentModerationResponse.moderationLabels().size());
                    for (ContentModerationDetection detectedLabel : contentModerationResponse.moderationLabels()) {
                        Map<String, String> labelMap = new HashMap<>();
                        ModerationLabel label = detectedLabel.moderationLabel();
                        labelMap.put("millisecond", String.valueOf(detectedLabel.timestamp()));
                        labelMap.put("name", label.name());
                        labelMap.put("confidence", label.confidence().toString());
                        String parents = label.parentName();
                        if (null != parents && !parents.isEmpty()) {
                            labelMap.put("parents", parents);
                        }
                        labels.add(labelMap);
                    }
                    return labels;
                }
            } else {
                return Collections.singletonList(Collections.singletonMap("ERROR", "Amazon Program Error"));
            }
        } catch (RekognitionException e) {
            log.error("error to get videoModerationDetectionResult;", e);
        }
        return null;
    }


    public void deleteMessage(String receiptHandle) {
        DeleteMessageRequest deleteMessageRequest = DeleteMessageRequest.builder()
                .queueUrl(queueUrl)
                .receiptHandle(receiptHandle)
                .build();
        sqs.deleteMessage(deleteMessageRequest);
    }

    public static void main(String[] args) {

//        System.out.println("https://images.letokenchat.cc/video/16518137/20240530173837545.mp4".substring(30));

        ProfileCredentialsProvider profileCredentialsProvider = ProfileCredentialsProvider
                .builder()
                .profileFile(ProfileFileSupplier.defaultSupplier())
                .build();


        rekClient = RekognitionClient.builder()
                .region(Region.AP_SOUTHEAST_1)
                .credentialsProvider(profileCredentialsProvider)
                .build();

        sqs = SqsClient.builder()
                .region(Region.AP_SOUTHEAST_1)
                .credentialsProvider(profileCredentialsProvider)
                .build();

        channel = NotificationChannel.builder()
                .snsTopicArn("arn:aws:sns:ap-southeast-1:144993035849:AmazonRekognitionVideoContentDetection")
                .roleArn("arn:aws:iam::144993035849:role/vediosns")
                .build();

//        testVideoModerationDetection();

//        testGetResultsModerationLabels("a01e57f59cf766ca4bccacfd2bb744df7f1fe838c2835d46fa3e6a3188229a6d");
        testVideoModerationDetectionResult("a01e57f59cf766ca4bccacfd2bb744df7f1fe838c2835d46fa3e6a3188229a6d");

//        System.out.println(receiveMessages());;
    }


    public static void testVideoModerationDetectionResult(String startJobId) {
        List<Message> messages;
        ReceiveMessageRequest messageRequest = ReceiveMessageRequest.builder()
//                .waitTimeSeconds(20)
                .queueUrl("https://sqs.ap-southeast-1.amazonaws.com/144993035849/VideoContentDetectionQueue")
                .build();

        try {
//            while (true) {
            messages = sqs.receiveMessage(messageRequest).messages();
            if (!messages.isEmpty()) {
                for (Message message : messages) {
                    String notification = message.body();
                    System.out.println(JSON.toJSONString(message));

                    // Get the status and job id from the notification
                    ObjectMapper mapper = new ObjectMapper();
                    JsonNode jsonMessageTree = mapper.readTree(notification);
                    JsonNode messageBodyText = jsonMessageTree.get("Message");
                    ObjectMapper operationResultMapper = new ObjectMapper();
                    JsonNode jsonResultTree = operationResultMapper.readTree(messageBodyText.textValue());
                    JsonNode operationJobId = jsonResultTree.get("JobId");
                    JsonNode operationStatus = jsonResultTree.get("Status");
                    System.out.println("Job found in JSON is " + operationJobId);

//                    DeleteMessageRequest deleteMessageRequest = DeleteMessageRequest.builder()
//                            .queueUrl("https://sqs.ap-southeast-1.amazonaws.com/144993035849/Video_Content_Detection_Queue.fifo")
//                            .build();

                    String jobId = operationJobId.textValue();
                    if (startJobId.compareTo(jobId) == 0) {
                        System.out.println("Job id: " + operationJobId);
                        System.out.println("Status : " + operationStatus.toString());

                        if (operationStatus.asText().equals("SUCCEEDED"))
                            testGetResultsLabels(startJobId);
                        else
                            System.out.println("Video analysis failed");

//                        sqs.deleteMessage(deleteMessageRequest);
                    } else {
                        System.out.println("Job received was not job " + startJobId);
//                        sqs.deleteMessage(deleteMessageRequest);
                    }
                }
//                    break;
            }
//            }
        } catch (RekognitionException e) {
            e.getMessage();
            System.exit(1);
        } catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        }
    }

    public static String testVideoModerationDetection() {

        S3Object s3Obj = S3Object.builder()
                .bucket("letoken")
                .name("video/16518001/20240530170213669.MP4")
                .build();

        Video vidOb = Video.builder()
                .s3Object(s3Obj)
                .build();

        StartContentModerationRequest labelDetectionRequest = StartContentModerationRequest.builder()
                .jobTag("DetectModerationLabels")
                .notificationChannel(channel)
                .video(vidOb)
                .minConfidence(50F)
                .build();

        StartContentModerationResponse response = rekClient.startContentModeration(labelDetectionRequest);
        System.out.println("JobId:" + response.jobId());
        return response.jobId();
    }


    // Gets the job results by calling GetLabelDetection
    private static void testGetResultsLabels(String startJobId) {

        int maxResults = 100;
        String paginationToken = null;
        GetLabelDetectionResponse labelDetectionResult = null;

        try {
//            do {
            if (labelDetectionResult != null)
                paginationToken = labelDetectionResult.nextToken();


            GetLabelDetectionRequest labelDetectionRequest = GetLabelDetectionRequest.builder()
                    .jobId(startJobId)
                    .sortBy(LabelDetectionSortBy.TIMESTAMP)
                    .maxResults(maxResults)
                    .nextToken(paginationToken)
                    .build();

            labelDetectionResult = rekClient.getLabelDetection(labelDetectionRequest);

//                System.out.println("????????????????????:" + JSON.toJSONString(labelDetectionResult.labels()));
            VideoMetadata videoMetaData = labelDetectionResult.videoMetadata();
            System.out.println("Format: " + videoMetaData.format());
            System.out.println("Codec: " + videoMetaData.codec());
            System.out.println("Duration: " + videoMetaData.durationMillis());
            System.out.println("FrameRate: " + videoMetaData.frameRate());

            List<LabelDetection> detectedLabels = labelDetectionResult.labels();
            for (LabelDetection detectedLabel : detectedLabels) {
                long seconds = detectedLabel.timestamp();
                Label label = detectedLabel.label();
                System.out.println("Millisecond: " + seconds + " ");

                System.out.println("   Label:" + label.name());
                System.out.println("   Confidence:" + detectedLabel.label().confidence().toString());

                List<Instance> instances = label.instances();
                System.out.println("   Instances of " + label.name());

                if (instances.isEmpty()) {
                    System.out.println("        " + "None");
                } else {
                    for (Instance instance : instances) {
                        System.out.println("        Confidence: " + instance.confidence().toString());
                        System.out.println("        Bounding box: " + instance.boundingBox().toString());
                    }
                }
                System.out.println("   Parent labels for " + label.name() + ":");
                List<Parent> parents = label.parents();

                if (parents.isEmpty()) {
                    System.out.println("        None");
                } else {
                    for (Parent parent : parents) {
                        System.out.println("   " + parent.name());
                    }
                }
                System.out.println();
            }
//            } while (labelDetectionResult.nextToken() != null);

        } catch (RekognitionException e) {
            e.printStackTrace();
            System.exit(1);
        }
    }


    private static void testGetResultsModerationLabels(String startJobId) {

        int maxResults = 10;
        String paginationToken = null;
        GetContentModerationResponse contentModerationResponse = null;

        try {
//            do {
            if (contentModerationResponse != null)
                paginationToken = contentModerationResponse.nextToken();


            GetContentModerationRequest contentModerationRequest = GetContentModerationRequest.builder()
                    .jobId(startJobId)
                    .maxResults(maxResults)
                    .nextToken(paginationToken)
                    .build();

            contentModerationResponse = rekClient.getContentModeration(contentModerationRequest);

//                System.out.println("????????????????????:" + JSON.toJSONString(labelDetectionResult.labels()));
            VideoMetadata videoMetaData = contentModerationResponse.videoMetadata();
            System.out.println("Format: " + videoMetaData.format());
            System.out.println("Codec: " + videoMetaData.codec());
            System.out.println("Duration: " + videoMetaData.durationMillis());
            System.out.println("FrameRate: " + videoMetaData.frameRate());

            List<ContentModerationDetection> detectedLabels = contentModerationResponse.moderationLabels();
            for (ContentModerationDetection detectedLabel : detectedLabels) {
                long seconds = detectedLabel.timestamp();
                ModerationLabel label = detectedLabel.moderationLabel();
                System.out.println("Millisecond: " + seconds + " ");

                System.out.println("   Label:" + label.name());
                System.out.println("   Confidence:" + detectedLabel.moderationLabel().confidence().toString());

//                List<Instance> instances = label.instances();
//                System.out.println("   Instances of " + label.name());

//                if (instances.isEmpty()) {
//                    System.out.println("        " + "None");
//                } else {
//                    for (Instance instance : instances) {
//                        System.out.println("        Confidence: " + instance.confidence().toString());
//                        System.out.println("        Bounding box: " + instance.boundingBox().toString());
//                    }
//                }
                System.out.println("   Parent labels for " + label.name() + ":");
                String parents = label.parentName();

                if (null == parents || parents.isEmpty()) {
                    System.out.println("        None");
                } else {
                    System.out.println("   " + parents);

                }
                System.out.println();
            }
//            } while (labelDetectionResult.nextToken() != null);

        } catch (RekognitionException e) {
            e.printStackTrace();
            System.exit(1);
        }
    }
}
